﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace XChipSerialPort
{
    public class I2CtoUsbManager
    {
        private uint mIndex; // USBIO 设备索引
        private const int SegmentSize = 2048; // 分段大小
        const uint StartAddr = 0x80b00ffc; // 起始地址
        const uint StartBddr = 0x80b02000; // 第二个起始地址

        // 定义委托类型
        public delegate void IndexCallback(int index);
        public event IndexCallback OnIndexProcessed;

        public delegate void MsgCallback(string Msg);
        public event MsgCallback OnMsgProcessed;

        public I2CtoUsbManager(uint usbIndex)
        {
            mIndex = usbIndex;
        }

        /// <summary>
        /// 发送单个字节的 I2C 数据
        /// </summary>
        /// <param name="subB">用于构建 I2C 数据的参数</param>
        /// <param name="data">要发送的数据</param>
        /// <param name="deviceNo">设备编号</param>
        /// <returns>成功发送返回 true，失败返回 false</returns>
        public bool SendSingleByteI2C(uint subB, uint[] data, byte deviceNo)
        {
            // 使用 UsbI2cWrite 方法发送单个字节
            return XChipUSB.UsbI2CBulkWrite( subB, data,Convert.ToUInt32( data.Count()), deviceNo); 
        }

        /// <summary>
        /// 获取单个字节的 I2C 数据
        /// </summary>
        /// <param name="subB">用于构建 I2C 数据的参数</param>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="readData">输出读取的数据</param>
        /// <returns>成功获取返回 true，失败返回 false</returns>
        public bool GetSingleByteI2C(uint subB, out uint[] readData, int array_size, byte deviceNo)
        {
            // 读取数据到一个数组中
            uint[] data = new uint[array_size];
            bool result = XChipUSB.UsbI2CBulkRead(subB, data,Convert.ToUInt32( array_size), deviceNo);
            readData = data; // 转换为 byte
            return result;
        }

        /// <summary>
        /// 解析文本文件
        /// </summary>
        public List<ParsedData> ParseAddresses(string filePath)
        {
            string fileContent = File.ReadAllText(filePath);
            var result = new List<ParsedData>();

            // 获取桌面路径
            string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            // 定义输出文件路径
            string outputPath = Path.Combine(desktopPath, "ParsedAddresses.txt");

            var lines = fileContent.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var line in lines)
            {
                var match = System.Text.RegularExpressions.Regex.Match(line.Trim(), @"^(0x[0-9A-Fa-f]+)(?:, \{(.+?)\}|, (.+?))?$");
                if (match.Success)
                {
                    string address = match.Groups[1].Value;
                    uint addr = Convert.ToUInt32(address, 16);
                    string values = match.Groups[2].Value;

                    var valueList = new List<uint>();
                    foreach (var value in values.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (uint.TryParse(value.Trim().Replace("0x", ""), System.Globalization.NumberStyles.HexNumber, null, out uint parsedValue))
                        {
                            valueList.Add(parsedValue);
                        }
                    }

                    // 处理的逻辑...
                    int valNo = (int)Math.Ceiling((double)valueList.Count / SegmentSize);
                    for (int i = 0; i < valNo; i++)
                    {
                        var segmentValues = valueList.Skip(i * SegmentSize).Take(SegmentSize).ToList();
                        var addrTemp = addr + (uint)(i * SegmentSize);

                        ParsedData parsedData = new ParsedData
                        {
                            address = addrTemp,
                            values = segmentValues,
                            fdbuf = new byte[4] { 0x00, 0xff, 0xfd, (byte)((addrTemp >> 24) & 0xff) },
                            febuf = new byte[4] { 0x00, 0xff, 0xfd, (byte)((addrTemp >> 16) & 0xff) }
                        };

                        result.Add(parsedData);
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 解析二进制文件
        /// </summary>
        public List<ParsedData> ParseBinAddresses(string filePath)
        {
            var result = new List<ParsedData>();
            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                byte[] buffer = new byte[4096];
                int bytesRead;
                uint currentAddress = 0;

                while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ParsedData data = new ParsedData
                    {
                        address = currentAddress,
                        values = new List<uint>(),
                        fdbuf = new byte[4] { 0x00, 0xff, 0xfd, (byte)((currentAddress >> 24) & 0xff) },
                        febuf = new byte[4] { 0x00, 0xff, 0xfd, (byte)((currentAddress >> 16) & 0xff) }
                    };

                    for (int i = 0; i < bytesRead; i++)
                    {
                        data.values.Add(buffer[i]);
                    }

                    result.Add(data);
                    currentAddress += (uint)bytesRead;
                }
            }

            return result;
        }

        public bool _isCancelled = false;
        public bool _isDebug = true;

        public void SendDataToBuffers(List<ParsedData> parsedDataList, byte deviceNo)
        {
            _isCancelled = false;

            try
            {
                // 发送初始数据
                if (!SendSingleByteI2C(0x80251000, new List<uint> { 0x1 }.ToArray(), deviceNo) || _isCancelled) return;
                if (!SendSingleByteI2C(0x80b00fec, new List<uint> { 0x1 }.ToArray(), deviceNo) || _isCancelled) return;

                StringBuilder msg = new StringBuilder();
                if (_isDebug && !_isCancelled)
                {
                    uint[] readData0 = new uint[1], readData1 = new uint[1], readData2 = new uint[1], readData3 = new uint[1], readData4 = new uint[1];
                    GetSingleByteI2C(0x20006df0, out readData0, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x20006df1, out readData1, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x20006df2, out readData2, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x20006df3, out readData3, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x20006df4, out readData4, array_size: 1, deviceNo);
                    msg.AppendLine($"0x{0x20006df0:X},0x{readData0[0]:X},0x{readData1[0]:X},0x{readData2[0]:X},0x{readData3[0]:X},0x{readData4[0]:X},"); msg.AppendLine("");
                    GetSingleByteI2C(0x8050000e, out readData3, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x2000000c, out readData4, array_size: 1, deviceNo);
                    msg.AppendLine($"0x{0x8050000e:X},0x{readData3[0]:X},0x{0x2000000c:X},0x{readData4[0]:X},");

                    OnMsgProcessed?.Invoke(msg.ToString());
                }

                // 主循环处理
                for (int i = 0; i < parsedDataList.Count && !_isCancelled; i++)
                {
                    if (_isCancelled) break;
                    if (i % 2 == 0)
                    {
                        SendDataToBuffer(parsedDataList[i], StartAddr, deviceNo, 0x80b00fee, 0x80b00ff0, 0x80b00ff8);
                    }
                    else
                    {
                        SendDataToBuffer(parsedDataList[i], StartBddr, deviceNo, 0x80b00fef, 0x80b00ff1, 0x80b01ffc);
                    }
                    OnIndexProcessed?.Invoke(i);
                }

                if (_isDebug && !_isCancelled)
                {
                    uint[] readData0 = new uint[1], readData1 = new uint[1], readData2 = new uint[1], readData3 = new uint[1], readData4 = new uint[1];
                    GetSingleByteI2C(0x20006df0, out readData0, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x20006df1, out readData1, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x20006df2, out readData2, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x20006df3, out readData3, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x20006df4, out readData4, array_size: 1, deviceNo);
                    msg.AppendLine($"0x{0x20006df0:X},0x{readData0[0]:X},0x{readData1[0]:X},0x{readData2[0]:X},0x{readData3[0]:X},0x{readData4[0]:X},"); msg.AppendLine("");
                    GetSingleByteI2C(0x8050000e, out readData3, array_size: 1, deviceNo);
                    GetSingleByteI2C(0x2000000c, out readData4, array_size: 1, deviceNo);
                    msg.AppendLine($"0x{0x8050000e:X},0x{readData3[0]:X},0x{0x2000000c:X},0x{readData4[0]:X},");

                    OnMsgProcessed?.Invoke(msg.ToString());
                }
            }
            finally
            {
                SendSingleByteI2C(0x80b00fec, new uint[] { 0x0 }, deviceNo);
                // 最终清理操作
                //SendSingleByteI2C(0x80b00fec, 0x0, deviceNo);
            }
        }

        public void SendDataToBuffer(ParsedData parsedData, uint startAddress, byte deviceNo, uint waitFlagAddress, uint errorFlagAddress, uint startAddressCommand)
        {
            // 等待缓冲区准备状态
            if (!WaitForBufferReady(waitFlagAddress, deviceNo)) { return; }

            // 发送缓冲区的起始地址
            if (_isCancelled || !SendSingleByteI2C(startAddressCommand, GetAddressData(parsedData.address).ToArray(), deviceNo))
            {
                return;
            }

            // 检查缓冲区等待标志
            if (!WaitForBufferReady(waitFlagAddress, deviceNo)) { return; }

            // 发送数据包
            if (!SendPacketsWithCheck(parsedData, startAddress, deviceNo))
            {
                return;
            }
            // 硬件处理时间约 100 毫秒
            Thread.Sleep(200);

            StringBuilder msg = new StringBuilder();
            msg.AppendLine($"------------- 分割线  --------");
            uint[] readDataArray = new uint[4]; // 用于接收数据的数组

            if (_isDebug && !_isCancelled)
            {
                // 发送等待标志，表示数据已准备好
                SendSingleByteI2C(waitFlagAddress, new uint[] { 0x1 }, deviceNo);
                Thread.Sleep(10);
                GetSingleByteI2C(waitFlagAddress, out readDataArray, 1, deviceNo);
                msg.AppendLine($"{waitFlagAddress:x},{readDataArray[0]:X},");
            }

            // 等待数据处理完成
            if (!WaitForDataProcessingCompletion(waitFlagAddress, deviceNo)) return;

            if (_isDebug && !_isCancelled)
            {
                
                    GetSingleByteI2C(startAddressCommand + (uint)(4), out readDataArray, 4, deviceNo);
               
                msg.AppendLine($"0x{startAddressCommand + 4:X},0x{readDataArray[0]:X},0x{readDataArray[1]:X},0x{readDataArray[2]:X},0x{readDataArray[3]:X},");

                SendSingleByteI2C(0x80b00ff2, new uint[] { (0x1000 >> 8) & 0xff }, deviceNo);
                msg.AppendLine($"-->0x80b00ff2,{Convert.ToUInt16(parsedData.values.Count).ToString("X")},");

                SendSingleByteI2C(0x80b00ff4,  GetAddressData(parsedData.address).ToArray(), deviceNo);
                msg.AppendLine($"-->0x80b00ff4,{parsedData.address:X},");
                SendSingleByteI2C(0x80b00fed, new uint[] { 0x1 }, deviceNo);
                msg.AppendLine($"-->0x80b00fed,0x1 ,");

                do
                {
                    Thread.Sleep(10);
                } while (GetSingleByteI2C(0x80b00fed, out readDataArray, 1, deviceNo) && readDataArray[0] != 0);

                GetSingleByteI2C(0x80b00ffc, out readDataArray, 4, deviceNo);
                msg.AppendLine($"0x{startAddressCommand + 4:X},0x{readDataArray[0]:X},0x{readDataArray[1]:X},0x{readDataArray[2]:X},0x{readDataArray[3]:X},");

                GetSingleByteI2C(errorFlagAddress, out readDataArray, 1, deviceNo);
                msg.AppendLine($"{errorFlagAddress:X},{readDataArray[0]:X},");

                OnMsgProcessed?.Invoke(msg.ToString());
            }

            // 检查错误和等待标志
            if (!_isCancelled && CheckErrorAndWait(errorFlagAddress, deviceNo, maxRetries: 5))
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine($"检查错误和等待标志");
                //SendSingleByteI2C(startAddressCommand, GetAddressData(parsedData.address)[0], deviceNo);
                sb.AppendLine($"{startAddressCommand:X},{parsedData.address:X}");
                sb.AppendLine($"{startAddressCommand:X},{parsedData.address:X}");
                SendSingleByteI2C(errorFlagAddress, new uint[] { 0x0 }, deviceNo);
                Thread.Sleep(300);
                SendSingleByteI2C(waitFlagAddress, new uint[] { 0x1 }, deviceNo);
                Thread.Sleep(200);
                OnMsgProcessed?.Invoke(sb.ToString());
            }
        }

        // 发送数据包的辅助方法
        private bool SendPacketsWithCheck(ParsedData data, uint startAddress, byte deviceNo)
        {
            // 计算总数据包数量
            int totalPackets = (int)Math.Ceiling((double)data.values.Count / SegmentSize);

            for (int j = 0; j < totalPackets && !_isCancelled; j++)
            {
                // 获取当前数据段
                var segment = data.values.Skip(j * SegmentSize).Take(SegmentSize).ToList();

                // 发送数据包
                if (!SendSingleByteI2C(startAddress + (uint)(j * SegmentSize), segment.ToArray(), deviceNo)) // 发送整个数据段
                {
                    return false; // 发送失败
                }
            }

            return !_isCancelled; // 返回是否被取消
        }

        // 检查错误和等待标志的方法
        private bool CheckErrorAndWait(uint errorFlagAddress, byte deviceNo, int maxRetries = 5)
        {
            uint[] readData = new uint[1]; // 创建输出数组
            int retryCount = 0;

            while (retryCount < maxRetries)
            {
                // 获取错误标志数据
                bool hasError = GetSingleByteI2C(errorFlagAddress, out readData, 1, deviceNo) && readData[0] != 0x0;

                if (hasError)
                {
                    // 设置休眠时间：如果剩余重试次数小于等于 2，休眠1500毫秒；否则休眠50毫秒
                    int sleepTime = (maxRetries - retryCount <= 2) ? 1500 : 50;
                    Thread.Sleep(sleepTime); // 等待设定时间
                    retryCount++; // 增加重试计数
                }
                else
                {
                    // 如果没有错误，退出循环
                    return false; // 返回 false 表示没有错误
                }
            }

            return true; // 返回 true 表示达到最大重试次数
        }


        /// <summary>
        /// 等待缓冲区准备就绪
        /// </summary>
        /// <param name="subB">等待标志的地址</param>
        /// <param name="deviceNo">设备编号</param>
        private bool WaitForBufferReady(uint subB, byte deviceNo)
        {
            DateTime startTime = DateTime.Now;
            uint[] readData = new uint[1]; // 创建输出数组

            do
            {
                if (_isCancelled) return false;
                if ((DateTime.Now - startTime).TotalSeconds > 10)
                {
                    OnMsgProcessed?.Invoke($"等待{subB:X}超时  {(DateTime.Now - startTime).TotalSeconds }秒");
                    _isCancelled = true;
                    return false;
                }
                Thread.Sleep(10);
            } while (GetSingleByteI2C(subB, out readData, 1, deviceNo) && readData[0] != 0x0); // 使用一维数组获取数据

            return !_isCancelled;
        }

        private bool WaitForDataProcessingCompletion(uint waitFlagAddress, byte deviceNo)
        {
            DateTime startTime = DateTime.Now;
            uint[] readData = new uint[1]; // 创建输出数组

            do
            {
                if (_isCancelled) return false;
                if ((DateTime.Now - startTime).TotalSeconds > 10)
                {
                    OnMsgProcessed?.Invoke($"处理{waitFlagAddress:X}超时 {(DateTime.Now - startTime).TotalSeconds }秒");
                    _isCancelled = true;
                    return false;
                }
                Thread.Sleep(10);
            } while (GetSingleByteI2C(waitFlagAddress, out readData, 1, deviceNo) && readData[0] != 0x0); // 使用一维数组获取数据

            return !_isCancelled;
        }

        public List<uint> GetAddressData(uint address)
        {
            return new List<uint>
            {
                (byte)((address >> 24) & 0xff),
                (byte)((address >> 16) & 0xff),
                (byte)((address >> 8) & 0xff),
                (byte)(address & 0xff)
            };
        }

        
    }
}
